﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace PersistanceLayer
{
    class InXmlRepository : IChatBoxDataRepository
    {
        private static readonly string _dataUsers = AppDomain.CurrentDomain.BaseDirectory + "/App_Data/users.xml";
        private static readonly string _dataMessages = AppDomain.CurrentDomain.BaseDirectory + "/App_Data/messages.xml";

        private static List<ChatBoxUserData> _users = new List<ChatBoxUserData>(); 
        private static List<ChatBoxMessageData> _messages = new List<ChatBoxMessageData>(); 

        private static void saveUsers()
        {
            lock (_dataUsers)
            {
                using (FileStream writer = File.Create(_dataUsers))
                {
                    XmlSerializer serializer = new XmlSerializer(_users.GetType());
                    serializer.Serialize(writer, _users);
                }
            }
        }

        private static void LoadUsers()
        {
            if (File.Exists(_dataUsers))
            {
                lock (_dataUsers)
                {
                    using (FileStream reader = File.Open(_dataUsers,
                             FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    {
                        XmlSerializer serializer = new XmlSerializer(_users.GetType());
                        try
                        {
                            _users = (List<ChatBoxUserData>)serializer.Deserialize(reader);
                        }
                        catch (InvalidOperationException)
                        {
                            return;
                        }
                    }
                }
            }
            else
            {
                _users = new List<ChatBoxUserData>();
                saveUsers();
            }
        }

        private static void saveMessages()
        {
            lock (_dataMessages)
            {
                using (FileStream writer = File.Create(_dataMessages))
                {
                    XmlSerializer serializer = new XmlSerializer(_messages.GetType());
                    serializer.Serialize(writer, _messages);
                }
            }
        }

        private static void loadMessages()
        {
            if (File.Exists(_dataMessages))
            {
                lock (_dataMessages)
                {
                    using (FileStream reader = File.Open(_dataMessages,
                             FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    {
                        
                        try
                        {
                            XmlSerializer serializer = new XmlSerializer(_messages.GetType());
                            _messages = (List<ChatBoxMessageData>)serializer.Deserialize(reader);
                        }
                        catch (InvalidOperationException)
                        {
                            return;
                        }
                    }
                }
            }
            else
            {
                _messages = new List<ChatBoxMessageData>();
                saveMessages();
            }
        }


        public List<IChatBoxUserData> GetAllUsersOnline()
        {
            LoadUsers();
            var tempList = new List<ChatBoxUserData>();
            foreach (var u in _users)
            {
                if (u.IsRegistered == false) tempList.Add(u);
                else if(u.IsOnline) tempList.Add(u);
            }
            return new List<IChatBoxUserData>(tempList);
        }

        public void ChangeIsOnlinePropertyWhenAppropriate(int thresholdInSeconds)
        {
            lock (_users)
            {
                LoadUsers();
                var usersCopy = new List<ChatBoxUserData>();
                foreach (var u in _users)
                {
                    var ts = DateTime.Now.Subtract(u.LastSeen);
                    if (ts.TotalSeconds < thresholdInSeconds)
                    {
                        u.IsOnline = true;
                        usersCopy.Add(u);
                    }
                    else if (u.IsRegistered)
                    {
                        u.IsOnline = false;
                        usersCopy.Add(u);
                    }                    
                }
                _users = usersCopy;
                saveUsers();
            }
        }

        public IChatBoxUserData AddUserWhenNameIsNew(string name, double lat, double lon, string iconUrl)
        {
            lock (_users){
                LoadUsers();
                var id = _users.Select(u => u.Id).Concat(new[] {1}).Max();
                var userData = new ChatBoxUserData(++id,name, iconUrl, true, "", lat, lon);
                var user = _users.ToList().Find(e => e.Name == name);
                if (user != null) return null;
                _users.Add(userData);
                saveUsers();
                return userData;
            }
        }

        public IChatBoxUserData AddUserWhenNameIsNew(string name, double lat, double lon, string iconUrl, string nickName)
        {
            lock (_users)
            {
                LoadUsers();
                var id = _users.Select(u => u.Id).Concat(new[] {1}).Max();
                var userData = new ChatBoxUserData(id,name, iconUrl, true, nickName, lat, lon);
                var user = _users.ToList().Find(e => e.Name == name);
                if (user != null) return null;
                _users.Add(userData);
                saveUsers();
                return userData;
            }
        }

        public void ClearUsers()
        {
            lock (_users)
            {
                _users = new List<ChatBoxUserData>();
                saveUsers();
            }
        }

        public void UpdateLastSeen(int id)
        {
            lock (_users)
            {
                LoadUsers();
                var user = _users.ToList().FindLast(e => e.Id == id);
                if (user == null)
                    return;
                user.LastSeen = DateTime.Now;
                saveUsers();
            }
        }


        public void LoginRegisteredUser(int id)
        {
            throw new NotImplementedException();
        }



        IList<IChatBoxMessageData> IChatBoxDataRepository.GetLastMessages(int id)
        {

            if (_users.Find(e => e.Id == id) == null) return new List<IChatBoxMessageData>();
            else
            {
                UpdateLastSeen(_users.Find(e => e.Id == id).Id);
                loadMessages();
                var lastMessages = _messages.Skip(Math.Max(0, _messages.Count() - 5)).Take(5);
                return lastMessages.Cast<IChatBoxMessageData>().ToList();
            }
        }


        public bool SendMessage(int id, string message)
        {
            LoadUsers();
            var user = _users.FindLast(e => e.Id == id);
            if (user != null)
            {
                lock (_messages)
                {
                    loadMessages();
                    _messages.Add(new ChatBoxMessageData(user,message));
                    saveMessages();
                    return true;
                }
            }
            else return false;
        }
    }
}
